home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Graphics / Ghostscript / source / gdevpdf.c < prev    next >
C/C++ Source or Header  |  1997-07-18  |  32KB  |  1,101 lines

  1. /* Copyright (C) 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevpdf.c */
  20. /* PDF-writing driver */
  21. #include "math_.h"
  22. #include "string_.h"
  23. #include "time_.h"
  24. #include "gx.h"
  25. #include "gp.h"
  26. #include "gscdefs.h"
  27. #include "gserrors.h"
  28. #include "gxdevice.h"
  29. #include "gxfixed.h"
  30. #include "gxistate.h"
  31. #include "gxpaint.h"
  32. #include "gzpath.h"
  33. #include "gzcpath.h"
  34. #include "gdevpdfx.h"
  35. #include "strimpl.h"        /* for short-sighted compilers */
  36. #include "scfx.h"        /* s_CFE_template is default */
  37.  
  38. /* Define the size of the internal stream buffer. */
  39. /* (This is not a limitation, it only affects performance.) */
  40. #define sbuf_size 512
  41.  
  42. /* GC descriptors */
  43. private_st_pdf_resource();
  44. private_st_pdf_font();
  45.  
  46. /* Device procedures */
  47. private dev_proc_open_device(pdf_open);
  48. private dev_proc_output_page(pdf_output_page);
  49. private dev_proc_close_device(pdf_close);
  50. private dev_proc_fill_rectangle(pdf_fill_rectangle);
  51. extern dev_proc_copy_mono(gdev_pdf_copy_mono);        /* in gdevpdfi.c */
  52. extern dev_proc_copy_color(gdev_pdf_copy_color);    /* in gdevpdfi.c */
  53. extern dev_proc_get_params(gdev_pdf_get_params);    /* in gdevpdfp.c */
  54. extern dev_proc_put_params(gdev_pdf_put_params);    /* in gdevpdfp.c */
  55. private dev_proc_fill_path(pdf_fill_path);
  56. private dev_proc_stroke_path(pdf_stroke_path);
  57. extern dev_proc_fill_mask(gdev_pdf_fill_mask);        /* in gdevpdfi.c */
  58. extern dev_proc_begin_image(gdev_pdf_begin_image);    /* in gdevpdfi.c */
  59. extern dev_proc_image_data(gdev_pdf_image_data);    /* in gdevpdfi.c */
  60. extern dev_proc_end_image(gdev_pdf_end_image);        /* in gdevpdfi.c */
  61.  
  62. #ifndef X_DPI
  63. #  define X_DPI 720
  64. #endif
  65. #ifndef Y_DPI
  66. #  define Y_DPI 720
  67. #endif
  68.  
  69. gx_device_pdf far_data gs_pdfwrite_device =
  70. {    std_device_color_body(gx_device_pdf, 0, "pdfwrite",
  71.       85*X_DPI/10, 110*Y_DPI/10, X_DPI, Y_DPI, 24, 255, 255),
  72.     {    pdf_open,
  73.         gx_upright_get_initial_matrix,
  74.         NULL,            /* sync_output */
  75.         pdf_output_page,
  76.         pdf_close,
  77.         gx_default_rgb_map_rgb_color,
  78.         gx_default_rgb_map_color_rgb,
  79.         pdf_fill_rectangle,
  80.         NULL,            /* tile_rectangle */
  81.         gdev_pdf_copy_mono,
  82.         gdev_pdf_copy_color,
  83.         NULL,            /* draw_line */
  84.         NULL,            /* get_bits */
  85.         gdev_pdf_get_params,
  86.         gdev_pdf_put_params,
  87.         NULL,            /* map_cmyk_color */
  88.         NULL,            /* get_xfont_procs */
  89.         NULL,            /* get_xfont_device */
  90.         NULL,            /* map_rgb_alpha_color */
  91.         gx_page_device_get_page_device,
  92.         NULL,            /* get_alpha_bits */
  93.         NULL,            /* copy_alpha */
  94.         NULL,            /* get_band */
  95.         NULL,            /* copy_rop */
  96.         pdf_fill_path,
  97.         pdf_stroke_path,
  98.         gdev_pdf_fill_mask,
  99.         NULL,            /* fill_trapezoid */
  100.         NULL,            /* fill_parallelogram */
  101.         NULL,            /* fill_triangle */
  102.         NULL,            /* draw_thin_line */
  103.         gdev_pdf_begin_image,
  104.         gdev_pdf_image_data,
  105.         gdev_pdf_end_image
  106.     },
  107.     psdf_initial_values(0 /*false*/),    /* (!ASCII85EncodePages) */
  108.     1.2,        /* CompatibilityLevel */
  109.     0/*false*/,    /* DoThumbnails */
  110.     1,        /* FirstObjectNumber */
  111.     0/*false*/,    /* binary_ok */
  112.      { 0 },        /* tfname */
  113.     0,        /* tfile */
  114.     0,        /* next_id */
  115.     0,        /* root_id */
  116.     0,        /* info_id */
  117.     0,        /* pages_id */
  118.     0,        /* outlines_id */
  119.     0,        /* next_page */
  120.      { 0 },        /* contents_ids */
  121.     0,        /* next_contents_id */
  122.     pdf_in_none,    /* context */
  123.     0,        /* contents_length_id */
  124.     0,        /* contents_pos */
  125.     NoMarks,    /* procsets */
  126.     -1,        /* flatness */
  127.      { gx_line_params_initial },    /* line_params */
  128.     0,        /* page_ids */
  129.     0,        /* num_page_ids */
  130.     0,        /* pages_referenced */
  131.      { 0 },        /* resources */
  132.     0,        /* annots */
  133.     0,        /* last_resource */
  134.      { 0, 0 },    /* catalog_string */
  135.      { 0, 0 },    /* pages_string */
  136.      { 0, 0 },    /* page_string */
  137.      { { { 0 } } },    /* outline_levels */
  138.     0,        /* outline_depth */
  139.     0,        /* closed_outline_depth */
  140.     0,        /* outlines_open */
  141.     0,        /* articles */
  142.     0,        /* named_dests */
  143.      { pdf_text_state_default }    /* text_state */
  144. };
  145.  
  146. /* ---------------- Utilities ---------------- */
  147.  
  148. /* ------ Document ------ */
  149.  
  150. /* Initialize the IDs allocated at startup. */
  151. void
  152. pdf_initialize_ids(gx_device_pdf *pdev)
  153. {    pdev->next_id = pdev->FirstObjectNumber;
  154.     pdev->root_id = pdf_obj_ref(pdev);
  155.     pdev->pages_id = pdf_obj_ref(pdev);
  156. }
  157.  
  158. /* Open the document if necessary. */
  159. void
  160. pdf_open_document(gx_device_pdf *pdev)
  161. {    stream *s = pdev->strm;
  162.  
  163.     if ( !is_in_document(pdev) && stell(s) == 0 )
  164.       { pputs(s, "%PDF-1.1\n");
  165.         pdev->binary_ok = !pdev->params.ASCII85EncodePages;
  166.         if ( pdev->binary_ok )
  167.           pputs(s, "%\307\354\217\242\n");
  168.       }
  169. }
  170.  
  171. /* ------ Objects ------ */
  172.  
  173. /* Allocate an object ID. */
  174. private long
  175. pdf_next_id(gx_device_pdf *pdev)
  176. {    return (pdev->next_id)++;
  177. }
  178.  
  179. /* Allocate an ID for a future object. */
  180. long
  181. pdf_obj_ref(gx_device_pdf *pdev)
  182. {    long id = pdf_next_id(pdev);
  183.     stream *s = pdev->strm;
  184.     long pos = stell(s);
  185.     FILE *tfile = pdev->tfile;
  186.  
  187.     fwrite(&pos, sizeof(pos), 1, tfile);
  188.     return id;
  189. }
  190.  
  191. /* Begin an object, optionally allocating an ID. */
  192. long
  193. pdf_open_obj(gx_device_pdf *pdev, long id)
  194. {    stream *s = pdev->strm;
  195.     FILE *tfile = pdev->tfile;
  196.  
  197.     if ( id <= 0 )
  198.       { id = pdf_obj_ref(pdev);
  199.       }
  200.     else
  201.       { long pos = stell(s);
  202.         long tpos = ftell(tfile);
  203.  
  204.         fseek(tfile, (id - pdev->FirstObjectNumber) * sizeof(pos),
  205.           SEEK_SET);
  206.         fwrite(&pos, sizeof(pos), 1, tfile);
  207.         fseek(tfile, tpos, SEEK_SET);
  208.       }
  209.     pprintld1(s, "%ld 0 obj\n", id);
  210.     return id;
  211. }
  212.  
  213. /* End an object. */
  214. int
  215. pdf_end_obj(gx_device_pdf *pdev)
  216. {    pputs(pdev->strm, "endobj\n");
  217.     return 0;
  218. }
  219.  
  220. /* ------ Graphics ------ */
  221.  
  222. /* Set the fill or stroke color. */
  223. int
  224. pdf_set_color(gx_device_pdf *pdev, gx_color_index color,
  225.   gx_drawing_color *pdcolor, const char *rgs)
  226. {    if ( gx_dc_pure_color(pdcolor) != color )
  227.       { color_set_pure(pdcolor, color);
  228.         psdf_set_color((gx_device_vector *)pdev, pdcolor, rgs);
  229.       }
  230.     return 0;
  231. }
  232.  
  233. /* Reset the graphics state parameters to initial values. */
  234. private void
  235. pdf_reset_graphics(gx_device_pdf *pdev)
  236. {    color_set_pure(&pdev->fill_color, 0);    /* black */
  237.     color_set_pure(&pdev->stroke_color, 0);    /* ditto */
  238.     pdev->flatness = -1;
  239.     { static const gx_line_params lp_initial = { gx_line_params_initial };
  240.       pdev->line_params = lp_initial;
  241.     }
  242. }
  243.  
  244. /* Set the scale for coordinates according to the current resolution. */
  245. void
  246. pdf_set_scale(gx_device_pdf *pdev)
  247. {    pdev->scale.x = pdev->HWResolution[0] / 72.0;
  248.     pdev->scale.y = pdev->HWResolution[1] / 72.0;
  249. }
  250.  
  251. /* ------ Page contents ------ */
  252.  
  253. /* Begin a page contents part. */
  254. /* Return an error if the page has too many contents parts. */
  255. int
  256. pdf_open_contents(gx_device_pdf *pdev, pdf_context context)
  257. {    stream *s = pdev->strm;
  258.  
  259.     if ( pdev->context == pdf_in_none )
  260.       { int next = pdev->next_contents_id;
  261.  
  262.         if ( next == max_contents_ids )
  263.           return_error(gs_error_limitcheck);
  264.         pdev->contents_ids[next] = pdf_begin_obj(pdev);
  265.         pdev->next_contents_id = next + 1;
  266.         pdev->contents_length_id = pdf_obj_ref(pdev);
  267.         pprintld1(s, "<< /Length %ld 0 R >>\n", pdev->contents_length_id);
  268.         pputs(s, "stream\n");
  269.         pdev->context = pdf_in_stream;
  270.         pdev->contents_pos = stell(s);
  271.         if ( next == 0 )
  272.           { /* Do a level of gsave for the clipping path. */
  273.         pputs(s, "q\n");
  274.           }
  275.       }
  276.     if ( pdev->context == context )
  277.       return 0;
  278.     switch ( context )
  279.     {
  280.     case pdf_in_text:
  281.       /* pdev->context must be pdf_in_stream */
  282.       pputs(s, "BT\n");
  283.       pdev->procsets |= Text;
  284.       break;
  285.     case pdf_in_stream:
  286.       /* pdev->context must be pdf_in_text */
  287.       pputs(s, "ET\n");
  288.       break;
  289.     /*case pdf_in_none:*/    /* not possible */
  290.     }
  291.     pdev->context = context;
  292.     return 0;
  293. }
  294.  
  295. /* Close the current contents part if we are in one. */
  296. int
  297. pdf_close_contents(gx_device_pdf *pdev, bool last)
  298. {    stream *s = pdev->strm;
  299.     long length;
  300.  
  301.     switch ( pdev->context )
  302.     {
  303.     case pdf_in_none:
  304.         return 0;
  305.     case pdf_in_text:
  306.         pputs(s, "ET\n");
  307.     case pdf_in_stream:
  308.         ;
  309.     }
  310.     if ( last )
  311.       { /* Exit from the clipping path gsave. */
  312.         pputs(s, "Q\n");
  313.         pdev->text_state.font = 0;
  314.       }
  315.     length = stell(s) - pdev->contents_pos;
  316.     pputs(s, "endstream\n");
  317.     pdf_end_obj(pdev);
  318.     pdf_open_obj(pdev, pdev->contents_length_id);
  319.     pprintld1(s, "%ld\n", length);
  320.     pdf_end_obj(pdev);
  321.     pdev->context = pdf_in_none;
  322.     return 0;
  323. }
  324.  
  325. /* ------ Resources et al ------ */
  326.  
  327. /* Define the names of the resource types. */
  328. private const char *resource_names[] =
  329.  { pdf_resource_type_names };
  330.  
  331. /* Define the allocator descriptors for the resource types. */
  332. private const gs_memory_struct_type_t *resource_structs[] =
  333.  { pdf_resource_type_structs };
  334.  
  335. /* Find a resource of a given type by gs_id. */
  336. pdf_resource *
  337. pdf_find_resource_by_gs_id(gx_device_pdf *pdev, pdf_resource_type type,
  338.   gs_id rid)
  339. {    pdf_resource **pprev = &pdev->resources[type];
  340.     pdf_resource *pres;
  341.  
  342.     for ( ; (pres = *pprev) != 0; pprev = &pres->next )
  343.       if ( pres->rid == rid )
  344.         { *pprev = pres->next;
  345.           pres->next = pdev->resources[type];
  346.           pdev->resources[type] = pres;
  347.           break;
  348.         }
  349.     return pres;
  350. }
  351.  
  352. /* Begin an aside (resource, annotation, ...). */
  353. int
  354. pdf_begin_aside(gx_device_pdf *pdev, pdf_resource **plist,
  355.   const gs_memory_struct_type_t *pst, pdf_resource **ppres)
  356. {    pdf_resource *pres;
  357.  
  358.     if ( pdev->context != pdf_in_none &&
  359.          pdev->next_contents_id == max_contents_ids
  360.        )
  361.       return_error(gs_error_limitcheck);
  362.     if ( pst == NULL )
  363.       pst = &st_pdf_resource;
  364.     pres =
  365.       gs_alloc_struct(pdev->pdf_memory, pdf_resource, pst, "begin_aside");
  366.     if ( pres == 0 )
  367.       return_error(gs_error_VMerror);
  368.     pdf_close_contents(pdev, false);
  369.     pdf_open_document(pdev);
  370.     pres->next = *plist;
  371.     *plist = pres;
  372.     pres->prev = pdev->last_resource;
  373.     pdev->last_resource = pres;
  374.     pres->id = pdf_begin_obj(pdev);
  375.     *ppres = pres;
  376.     return 0;
  377. }
  378. /* Begin a resource of a given type. */
  379. int
  380. pdf_begin_resource(gx_device_pdf *pdev, pdf_resource_type type,
  381.   pdf_resource **ppres)
  382. {    stream *s = pdev->strm;
  383.     int code = pdf_begin_aside(pdev, &pdev->resources[type],
  384.                    resource_structs[type], ppres);
  385.  
  386.     if ( code < 0 )
  387.       return code;
  388.     pprints1(s, "<< /Type /%s", resource_names[type]);
  389.     pprintld1(s, " /Name /R%ld", (*ppres)->id);
  390.     return code;
  391. }
  392.  
  393. /* End an aside. */
  394. int
  395. pdf_end_aside(gx_device_pdf *pdev)
  396. {    return pdf_end_obj(pdev);
  397. }
  398. /* End a resource. */
  399. int
  400. pdf_end_resource(gx_device_pdf *pdev)
  401. {    return pdf_end_aside(pdev);
  402. }
  403.  
  404. /* ------ Pages ------ */
  405.  
  406. /* Reset the state of the current page. */
  407. void
  408. pdf_reset_page(gx_device_pdf *pdev)
  409. {    pdev->next_contents_id = 0;
  410.     pdf_reset_graphics(pdev);
  411.     pdev->procsets = NoMarks;
  412.     { int i;
  413.       for ( i = 0; i < num_resource_types; ++i )
  414.         pdev->resources[i] = 0;
  415.     }
  416.     pdev->page_string.data = 0;
  417.     { static const pdf_text_state text_default =
  418.        { pdf_text_state_default };
  419.       pdev->text_state = text_default;
  420.     }
  421. }
  422.  
  423. /* Get or assign the ID for a page. */
  424. /* Returns 0 if the page number is out of range. */
  425. long
  426. pdf_page_id(gx_device_pdf *pdev, int page_num)
  427. {    long page_id;
  428.  
  429.     if ( page_num >= pdev->num_page_ids )
  430.       { /* Grow the page_ids array. */
  431.         uint new_num_ids =
  432.           max(page_num + 10, pdev->num_page_ids << 1);
  433.         /* resize_object for a byte array takes a new object size */
  434.         /* in bytes.  This is a quirk of the API that we probably */
  435.         /* won't ever be able to fix.... */
  436.         long *new_ids = gs_resize_object(pdev->pdf_memory, pdev->page_ids,
  437.                          new_num_ids * sizeof(long),
  438.                          "pdf_page_id(resize page_ids)");
  439.  
  440.         if ( new_ids == 0 )
  441.           return 0;
  442.         pdev->page_ids = new_ids;
  443.         pdev->num_page_ids = new_num_ids;
  444.       }
  445.     if ( page_num < 1 )
  446.       return 0;
  447.     while ( page_num > pdev->pages_referenced )
  448.       pdev->page_ids[pdev->pages_referenced++] = 0;
  449.     if ( (page_id = pdev->page_ids[page_num - 1]) == 0 )
  450.       pdev->page_ids[page_num - 1] = page_id = pdf_obj_ref(pdev);
  451.     return page_id;
  452. }
  453.  
  454. /* Write saved page- or document-level information. */
  455. int
  456. pdf_write_saved_string(gx_device_pdf *pdev, gs_string *pstr)
  457. {    if ( pstr->data != 0 )
  458.       { pwrite(pdev->strm, pstr->data, pstr->size);
  459.         gs_free_string(pdev->pdf_memory, pstr->data, pstr->size,
  460.                "pdf_write_saved_string");
  461.         pstr->data = 0;
  462.       }
  463.     return 0;
  464. }
  465.  
  466. /* Open a page for writing. */
  467. int
  468. pdf_open_page(gx_device_pdf *pdev, pdf_context context)
  469. {    if ( !is_in_page(pdev) )
  470.       { if ( pdf_page_id(pdev, pdev->next_page + 1) == 0 )
  471.           return_error(gs_error_VMerror);
  472.         pdf_open_document(pdev);
  473.       }
  474.     return (context != pdf_in_none ? pdf_open_contents(pdev, context) :
  475.         pdf_close_contents(pdev, false));
  476. }
  477.  
  478. /* Close the current page. */
  479. private int
  480. pdf_close_page(gx_device_pdf *pdev)
  481. {    stream *s = pdev->strm;
  482.     int page_num = ++(pdev->next_page);
  483.     long page_id;
  484.  
  485.     /* If the very first page is blank, we need to open the document */
  486.     /* before doing anything else. */
  487.     pdf_open_document(pdev);
  488.     pdf_close_contents(pdev, true);
  489.     page_id = pdf_page_id(pdev, page_num);
  490.     pdf_open_obj(pdev, page_id);
  491.     pprintd2(s, "<<\n/Type /Page\n/MediaBox [0 0 %d %d]\n",
  492.          (int)(pdev->MediaSize[0]), (int)(pdev->MediaSize[1]));
  493.     pprintld1(s, "/Parent %ld 0 R\n", pdev->pages_id);
  494.     pputs(s, "/Resources << /ProcSet [/PDF");
  495.     if ( pdev->procsets & ImageB )
  496.       pputs(s, " /ImageB");
  497.     if ( pdev->procsets & ImageC )
  498.       pputs(s, " /ImageC");
  499.     if ( pdev->procsets & ImageI )
  500.       pputs(s, " /ImageI");
  501.     if ( pdev->procsets & Text )
  502.       pputs(s, " /Text");
  503.     pputs(s, "]\n");
  504.     { int i;
  505.       for ( i = 0; i < num_resource_types; ++i )
  506.         { const pdf_resource *pres = pdev->resources[i];
  507.           if ( pres != 0 )
  508.         { pprints1(s, "/%s <<\n", resource_names[i]);
  509.           for ( ; pres; pres = pres->next )
  510.             pprintld2(s, "/R%ld %ld 0 R\n", pres->id, pres->id);
  511.           pputs(s, ">>\n");
  512.         }
  513.           pdev->resources[i] = 0;
  514.         }
  515.     }
  516.     pputs(s, ">>\n");
  517.     if ( pdev->next_contents_id == 1 )
  518.       pprintld1(s, "/Contents %ld 0 R\n", pdev->contents_ids[0]);
  519.     else
  520.       { int i;
  521.         pputs(s, "/Contents [\n");
  522.         for ( i = 0; i < pdev->next_contents_id; ++i )
  523.           pprintld1(s, "%ld 0 R\n", pdev->contents_ids[i]);
  524.         pputs(s, "]\n");
  525.       }
  526.     pdf_write_saved_string(pdev, &pdev->page_string);
  527.     { const pdf_resource *pres = pdev->annots;
  528.       bool any = false;
  529.       for ( ; pres != 0; pres = pres->next )
  530.         if ( pres->rid == page_num - 1 )
  531.           { if ( !any )
  532.           { pputs(s, "/Annots [\n");
  533.             any = true;
  534.           }
  535.         pprintld1(s, "%ld 0 R\n", pres->id);
  536.           }
  537.       if ( any )
  538.         pputs(s, "]\n");
  539.     }
  540.     pputs(s, ">>\n");
  541.     pdf_end_obj(pdev);
  542.     pdf_reset_page(pdev);
  543.     return 0;
  544. }
  545.  
  546. /* Write the default entries of the Info dictionary. */
  547. int
  548. pdf_write_default_info(gx_device_pdf *pdev)
  549. {    stream *s = pdev->strm;
  550.     /* Reading the time without using time_t is a challenge.... */
  551.     long t[2];    /* time_t can't be longer than 2 longs. */
  552.     struct tm ltime;
  553.     char buf[20];
  554.  
  555.     time((void *)t);
  556.     ltime = *localtime((void *)t);
  557.     sprintf(buf, "%04d%02d%02d%02d%02d%02d",
  558.         ltime.tm_year + 1900, ltime.tm_mon + 1, ltime.tm_mday,
  559.         ltime.tm_hour, ltime.tm_min, ltime.tm_sec);
  560.     pprints1(s, "/CreationDate (D:%s)\n", buf);
  561.     sprintf(buf, "%1.2f", gs_revision / 100.0);
  562.     pprints2(s, "/Producer (%s %s)\n", gs_product, buf);
  563.     return 0;
  564. }
  565.  
  566. /* ---------------- Device open/close ---------------- */
  567.  
  568. /* Open the device. */
  569. private int
  570. pdf_open(gx_device *dev)
  571. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  572.     char fmode[4];
  573.     int code;
  574.  
  575.     pdev->pdf_memory = &gs_memory_default;        /* as good as any */
  576.     strcpy(fmode, "w+");
  577.     strcat(fmode, gp_fmode_binary_suffix);
  578.     pdev->tfile =
  579.       gp_open_scratch_file(gp_scratch_file_name_prefix,
  580.                    pdev->tfname, fmode);
  581.     if ( pdev->tfile == 0 )
  582.       return_error(gs_error_invalidfileaccess);
  583.     code = gdev_vector_open_file((gx_device_vector *)pdev, sbuf_size);
  584.     if ( code < 0 )
  585.       goto fail;
  586.     gdev_vector_init((gx_device_vector *)pdev);
  587.     /* Set in_page so the vector routines won't try to call */
  588.     /* any vector implementation procedures. */
  589.     pdev->in_page = true;
  590.     pdf_set_scale(pdev);
  591.     pdf_initialize_ids(pdev);
  592.     pdev->outlines_id = 0;
  593.     pdev->next_page = 0;
  594.     pdev->page_ids = (void *)
  595.       gs_alloc_byte_array(pdev->pdf_memory, initial_num_page_ids,
  596.                   sizeof(*pdev->page_ids), "pdf_open(page_ids)");
  597.     if ( pdev->page_ids == 0 )
  598.       { code = gs_error_VMerror;
  599.         goto fail;
  600.       }
  601.     pdev->num_page_ids = initial_num_page_ids;
  602.     pdev->pages_referenced = 0;
  603.     pdev->catalog_string.data = 0;
  604.     pdev->pages_string.data = 0;
  605.     pdev->outline_levels[0].first.id = 0;
  606.     pdev->outline_levels[0].left = max_int;
  607.     pdev->outline_depth = 0;
  608.     pdev->closed_outline_depth = 0;
  609.     pdev->outlines_open = 0;
  610.     pdev->articles = 0;
  611.     pdev->named_dests = 0;
  612.     pdf_reset_page(pdev);
  613.  
  614.     return 0;
  615. fail:
  616.     fclose(pdev->tfile);
  617.     unlink(pdev->tfname);
  618.     pdev->tfile = 0;
  619.     return code;
  620. }
  621.  
  622. /* Wrap up ("output") a page. */
  623. private int
  624. pdf_output_page(gx_device *dev, int num_copies, int flush)
  625. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  626.     return pdf_close_page(pdev);
  627. }
  628.  
  629. /* Close the device. */
  630. private int
  631. pdf_close(gx_device *dev)
  632. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  633.     stream *s = pdev->strm;
  634.     FILE *tfile = pdev->tfile;
  635.     long xref;
  636.     long named_dests_id = 0;
  637.  
  638.     /*
  639.      * If this is an EPS file, we need to tidy up a little so as not
  640.      * to produce illegal PDF.  We recognize EPS files as having some
  641.      * contents but no showpage.
  642.      */
  643.     if ( pdev->next_page == 0 && pdev->next_contents_id != 0 )
  644.       { pdf_close_page(pdev);
  645.       }
  646.  
  647.     /* Create the root (Catalog). */
  648.     pdf_open_obj(pdev, pdev->pages_id);
  649.     pputs(s, "<< /Type /Pages /Kids [\n");
  650.     { int i;
  651.       for ( i = 0; i < pdev->next_page; ++i )
  652.         pprintld1(s, "%ld 0 R\n", pdev->page_ids[i]);
  653.     }
  654.     pprintd1(s, "] /Count %d\n", pdev->next_page);
  655.     pdf_write_saved_string(pdev, &pdev->pages_string);
  656.     pputs(s, ">>\n");
  657.     pdf_end_obj(pdev);
  658.     if ( pdev->outlines_id != 0 )
  659.       { pdfmark_close_outline(pdev);    /* depth must be zero! */
  660.         pdf_open_obj(pdev, pdev->outlines_id);
  661.         pprintd1(s, "<< /Count %d", pdev->outlines_open);
  662.         pprintld2(s, " /First %ld 0 R /Last %ld 0 R >>\n",
  663.               pdev->outline_levels[0].first.id,
  664.               pdev->outline_levels[0].last.id);
  665.         pdf_end_obj(pdev);
  666.       }
  667.     if ( pdev->articles != 0 )
  668.       { pdf_article *part;
  669.         /* Write the first and last beads of each article. */
  670.         for ( part = pdev->articles; part != 0; part = part->next )
  671.           { if ( part->last.id == 0 )
  672.           { /* Only one bead in the article. */
  673.             part->first.prev_id = part->first.next_id = part->first.id;
  674.           }
  675.         else
  676.           { /* More than one bead in the article. */
  677.             part->first.prev_id = part->last.id;
  678.             part->last.next_id = part->first.id;
  679.             pdfmark_write_article(pdev, &part->last);
  680.           }
  681.         pdfmark_write_article(pdev, &part->first);
  682.           }
  683.       }
  684.     if ( pdev->named_dests != 0 )
  685.       { pdf_named_dest *pnd;
  686.         named_dests_id = pdf_begin_obj(pdev);
  687.         pputs(s, "<<\n");
  688.         while ( (pnd = pdev->named_dests) != 0 )
  689.           { pdev->named_dests = pnd->next;
  690.         pwrite(s, pnd->key.data, pnd->key.size);
  691.         pprints1(s, " %s\n", pnd->dest);
  692.         gs_free_string(pdev->pdf_memory, pnd->key.data, pnd->key.size,
  693.                    "pdf_close(named_dest key)");
  694.         gs_free_object(pdev->pdf_memory, pnd, "pdf_close(named_dest)");
  695.           }
  696.         pputs(s, ">>\n");
  697.         pdf_end_obj(pdev);
  698.       }
  699.     pdf_open_obj(pdev, pdev->root_id);
  700.     pprintld1(s, "<< /Type /Catalog /Pages %ld 0 R\n", pdev->pages_id);
  701.     if ( pdev->outlines_id != 0 )
  702.       pprintld1(s, "/Outlines %ld 0 R\n", pdev->outlines_id);
  703.     if ( pdev->articles != 0 )
  704.       { pdf_article *part;
  705.         pputs(s, "/Threads [ ");
  706.         while ( (part = pdev->articles) != 0 )
  707.           { pdev->articles = part->next;
  708.         pprintld1(s, "%ld 0 R\n", part->id);
  709.         gs_free_string(pdev->pdf_memory, part->title.data,
  710.                    part->title.size, "pdf_close(article title)");
  711.         gs_free_object(pdev->pdf_memory, part, "pdf_close(article)");
  712.           }
  713.         pputs(s, "]\n");
  714.       }
  715.     if ( named_dests_id != 0 )
  716.       pprintld1(s, "/Dests %ld 0 R\n", named_dests_id);
  717.     pdf_write_saved_string(pdev, &pdev->catalog_string);
  718.     pputs(s, ">>\n");
  719.     pdf_end_obj(pdev);
  720.  
  721.     /* Create the Info directory. */
  722.     /* This is supposedly optional, but some readers may require it. */
  723.     if ( pdev->info_id == 0 )
  724.       { pdev->info_id = pdf_begin_obj(pdev);
  725.         pputs(s, "<< ");
  726.         pdf_write_default_info(pdev);
  727.         pputs(s, ">>\n");
  728.         pdf_end_obj(pdev);
  729.     }
  730.  
  731.     /* Write the cross-reference section. */
  732.     xref = stell(s);
  733.     if ( pdev->FirstObjectNumber == 1 )
  734.       pprintld1(s, "xref\n0 %ld\n0000000000 65535 f \n",
  735.             pdev->next_id);
  736.     else
  737.       pprintld2(s, "xref\n0 1\n0000000000 65535 f \n%ld %ld\n",
  738.             pdev->FirstObjectNumber,
  739.             pdev->next_id - pdev->FirstObjectNumber);
  740.     fseek(tfile, 0L, SEEK_SET);
  741.     { long i;
  742.       for ( i = pdev->FirstObjectNumber; i < pdev->next_id; ++i )
  743.         { ulong pos;
  744.           char str[21];
  745.  
  746.           fread(&pos, sizeof(pos), 1, tfile);
  747.           sprintf(str, "%010ld 00000 n \n", pos);
  748.           pputs(s, str);
  749.         }
  750.     }
  751.  
  752.     /* Write the trailer. */
  753.     pputs(s, "trailer\n");
  754.     pprintld3(s, "<< /Size %ld /Root %ld 0 R /Info %ld 0 R\n",
  755.           pdev->next_id, pdev->root_id, pdev->info_id);
  756.     pputs(s, ">>\n");
  757.     pprintld1(s, "startxref\n%ld\n%%%%EOF\n", xref);
  758.  
  759.     /* Release the resource records. */
  760.     { pdf_resource *pres;
  761.       pdf_resource *prev;
  762.       for ( prev = pdev->last_resource; (pres = prev) != 0; )
  763.         { prev = pres->prev;
  764.           gs_free_object(pdev->pdf_memory, pres, "pdf_resource");
  765.         }
  766.       pdev->last_resource = 0;
  767.     }
  768.  
  769.     gs_free_object(pdev->pdf_memory, pdev->page_ids, "page_ids");
  770.     pdev->page_ids = 0;
  771.     pdev->num_page_ids = 0;
  772.  
  773.     gdev_vector_close_file((gx_device_vector *)pdev);
  774.     fclose(pdev->tfile);
  775.     pdev->tfile = 0;
  776.     unlink(pdev->tfname);
  777.     return 0;
  778. }
  779.  
  780. /* ---------------- Drawing ---------------- */
  781.  
  782. /* Fill a rectangle. */
  783. private int
  784. pdf_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  785.   gx_color_index color)
  786. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  787.     stream *s = pdev->strm;
  788.     int code;
  789.  
  790.     /* Make a special check for the initial fill with white, */
  791.     /* which shouldn't cause the page to be opened. */
  792.     if ( color == 0xffffff && !is_in_page(pdev) )
  793.       return 0;
  794.     code = pdf_open_page(pdev, pdf_in_stream);
  795.     if ( code < 0 )
  796.       return code;
  797.     /* Make sure we aren't being clipped. */
  798.     pdf_put_clip_path(pdev, NULL);
  799.     pdf_set_color(pdev, color, &pdev->fill_color, "rg");
  800.     pprintg4(s, "%g %g %g %g re\nf\n",
  801.          x / pdev->scale.x, y / pdev->scale.y,
  802.          w / pdev->scale.x, h / pdev->scale.y);
  803.     return 0;
  804. }
  805.  
  806. /* ---------------- Path drawing ---------------- */
  807.  
  808. /* ------ Utilities ------ */
  809.  
  810. /* Put a path on the output file.  If do_close is false and the last */
  811. /* path component is a closepath, omit it and return 1. */
  812. private int
  813. pdf_put_path(gx_device_pdf *pdev, const gx_path *ppath, bool do_close,
  814.   const gs_matrix *pmat)
  815. {    stream *s = pdev->strm;
  816.     gs_fixed_rect rbox;
  817.     const subpath *next;
  818.     gs_path_enum cenum;
  819.  
  820.     /* If do_close is false, we recognize rectangles specially. */
  821.     if ( !do_close && ppath->subpath_count == 1 &&
  822.          ppath->curve_count == 0 &&
  823.          gx_subpath_is_rectangle(ppath->first_subpath, &rbox, &next)
  824.        )
  825.       {    gs_point p, q;
  826.         p.x = fixed2float(rbox.p.x), p.y = fixed2float(rbox.p.y);
  827.         q.x = fixed2float(rbox.q.x), q.y = fixed2float(rbox.q.y);
  828.         if ( pmat )
  829.           { gs_point_transform_inverse(p.x, p.y, pmat, &p);
  830.             gs_point_transform_inverse(q.x, q.y, pmat, &q);
  831.           }
  832.         pprintg4(s, "%g %g %g %g re\n",
  833.              p.x / pdev->scale.x, p.y / pdev->scale.y,
  834.              (q.x - p.x) / pdev->scale.x,
  835.              (q.y - p.y) / pdev->scale.y);
  836.         return 0;
  837.       }
  838.     gx_path_enum_init(&cenum, ppath);
  839.     for ( ; ; )
  840.       { fixed vs[6];
  841.         gs_point vp[3];
  842.         const char *format;
  843.         int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *)vs);
  844.  
  845. sw:        switch ( pe_op )
  846.           {
  847.           case 0:        /* done */
  848.         return 0;
  849.           case gs_pe_moveto:
  850.         format = "%g %g m\n";
  851.         goto do1;
  852.           case gs_pe_lineto:
  853.         format = "%g %g l\n";
  854. do1:        vp[0].x = fixed2float(vs[0]), vp[0].y = fixed2float(vs[1]);
  855.         if ( pmat )
  856.           gs_point_transform_inverse(vp[0].x, vp[0].y, pmat, &vp[0]);
  857.         pprintg2(s, format,
  858.              vp[0].x / pdev->scale.x, vp[0].y / pdev->scale.y);
  859.         break;
  860.           case gs_pe_curveto:
  861.         vp[0].x = fixed2float(vs[0]), vp[0].y = fixed2float(vs[1]);
  862.         vp[1].x = fixed2float(vs[2]), vp[1].y = fixed2float(vs[3]);
  863.         vp[2].x = fixed2float(vs[4]), vp[2].y = fixed2float(vs[5]);
  864.         if ( pmat )
  865.           { gs_point_transform_inverse(vp[0].x, vp[0].y, pmat, &vp[0]);
  866.             gs_point_transform_inverse(vp[1].x, vp[1].y, pmat, &vp[1]);
  867.             gs_point_transform_inverse(vp[2].x, vp[2].y, pmat, &vp[2]);
  868.           }
  869.         pprintg6(s, "%g %g %g %g %g %g c\n",
  870.              vp[0].x / pdev->scale.x, vp[0].y / pdev->scale.y,
  871.              vp[1].x / pdev->scale.x, vp[1].y / pdev->scale.y,
  872.              vp[2].x / pdev->scale.x, vp[2].y / pdev->scale.y);
  873.         break;
  874.           case gs_pe_closepath:
  875.         if ( do_close )
  876.           { pputs(s, "h\n");
  877.             break;
  878.           }
  879.         pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *)vs);
  880.         if ( pe_op != 0 )
  881.           { pputs(s, "h\n");
  882.             goto sw;
  883.           }
  884.         return 1;
  885.           }
  886.       }
  887. }
  888.  
  889. /* Test whether we will need to put the clipping path. */
  890. private bool
  891. pdf_must_put_clip_path(gx_device_pdf *pdev, const gx_clip_path *pcpath)
  892. {    if ( pcpath == NULL )
  893.       return pdev->clip_path_id != pdev->no_clip_path_id;
  894.     if ( pdev->clip_path_id == pcpath->id )
  895.       return false;
  896.     if ( gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
  897.                      int2fixed(pdev->width),
  898.                      int2fixed(pdev->height))
  899.        )
  900.       return pdev->clip_path_id != pdev->no_clip_path_id;
  901.     return true;
  902. }
  903.  
  904. /* Put a clipping path on the output file. */
  905. int
  906. pdf_put_clip_path(gx_device_pdf *pdev, const gx_clip_path *pcpath)
  907. {    stream *s = pdev->strm;
  908.  
  909.     if ( pcpath == NULL ) {
  910.       if ( pdev->clip_path_id == pdev->no_clip_path_id )
  911.         return 0;
  912.       pputs(s, "Q\nq\n");
  913.       pdev->clip_path_id = pdev->no_clip_path_id;
  914.     } else {
  915.       if ( pdev->clip_path_id == pcpath->id )
  916.         return 0;
  917.       if ( gx_cpath_includes_rectangle(pcpath, fixed_0, fixed_0,
  918.                        int2fixed(pdev->width),
  919.                        int2fixed(pdev->height))
  920.          ) {
  921.         if ( pdev->clip_path_id == pdev->no_clip_path_id )
  922.           return 0;
  923.         pputs(s, "Q\nq\n");
  924.         pdev->clip_path_id = pdev->no_clip_path_id;
  925.       } else {
  926.         pputs(s, "Q\nq\nW\n");
  927.         if ( pcpath->segments_valid )
  928.           pdf_put_path(pdev, &pcpath->path, true, NULL);
  929.         else
  930.           { /* Write out the rectangles. */
  931.         const gx_clip_rect *prect = pcpath->list.head;
  932.  
  933.         if ( prect == 0 )
  934.           prect = &pcpath->list.single;
  935.         for ( ; prect != 0; prect = prect->next )
  936.           if ( prect->xmax > prect->xmin && prect->ymax > prect->ymin )
  937.             pprintg4(s, "%g %g %g %g re\n",
  938.                  prect->xmin / pdev->scale.x,
  939.                  prect->ymin / pdev->scale.y,
  940.                  (prect->xmax - prect->xmin) / pdev->scale.x,
  941.                  (prect->ymax - prect->ymin) / pdev->scale.y);
  942.           }
  943.         pputs(s, "n\n");
  944.         pdev->clip_path_id = pcpath->id;
  945.       }
  946.     }
  947.     pdev->text_state.font = 0;
  948.     if ( pdev->context == pdf_in_text )
  949.       pdev->context = pdf_in_stream;
  950.     pdf_reset_graphics(pdev);
  951.     return 0;
  952. }
  953.  
  954. /* ------ Driver procedures ------ */
  955.  
  956. /* Fill a path. */
  957. private int
  958. pdf_fill_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
  959.   const gx_fill_params *params,
  960.   const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
  961. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  962.     stream *s = pdev->strm;
  963.     int code;
  964.     /*
  965.      * HACK: we fill an empty path in order to set the clipping path
  966.      * and the color for writing text.  If it weren't for this, we
  967.      * could detect and skip empty paths before putting out the clip
  968.      * path or the color.
  969.      */
  970.     bool have_path = !gx_path_is_void(ppath);
  971.  
  972.     if ( !gx_dc_is_pure(pdcolor) )
  973.       return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
  974.                       pcpath);
  975.     /*
  976.      * Make a special check for the initial fill with white,
  977.      * which shouldn't cause the page to be opened.
  978.      */
  979.     if ( gx_dc_pure_color(pdcolor) == 0xffffff && !is_in_page(pdev) )
  980.       return 0;
  981.     if ( have_path || pdev->context == pdf_in_none ||
  982.          pdf_must_put_clip_path(pdev, pcpath)
  983.        )
  984.       { code = pdf_open_page(pdev, pdf_in_stream);
  985.         if ( code < 0 )
  986.           return code;
  987.       }
  988.     pdf_put_clip_path(pdev, pcpath);
  989.     pdf_set_color(pdev, gx_dc_pure_color(pdcolor), &pdev->fill_color, "rg");
  990.     if ( have_path )
  991.       { if ( params->flatness != pdev->flatness )
  992.           { pprintg1(s, "%g i\n", params->flatness);
  993.             pdev->flatness = params->flatness;
  994.           }
  995.         pdf_put_path(pdev, ppath, false, NULL);
  996.         pputs(s, (params->rule < 0 ? "f\n" : "f*\n"));
  997.       }
  998.     return 0;
  999. }
  1000.  
  1001. /* Compare two dash patterns. */
  1002. private bool
  1003. pdf_dash_pattern_eq(const float *stored, const gx_dash_params *set, float scale)
  1004. {    int i;
  1005.     for ( i = 0; i < set->pattern_size; ++i )
  1006.       if ( stored[i] != (float)(set->pattern[i] * scale) )
  1007.         return false;
  1008.     return true;
  1009. }
  1010.  
  1011. /* Stroke a path. */
  1012. private int
  1013. pdf_stroke_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
  1014.   const gx_stroke_params *params,
  1015.   const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
  1016. {    gx_device_pdf *pdev = (gx_device_pdf *)dev;
  1017.     stream *s = pdev->strm;
  1018.     int code;
  1019.     int pattern_size = pis->line_params.dash.pattern_size;
  1020.     double scale;
  1021.     int i;
  1022.  
  1023.     if ( !gx_dc_is_pure(pdcolor) )
  1024.       return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
  1025.                     pcpath);
  1026.     code = pdf_open_page(pdev, pdf_in_stream);
  1027.     if ( code < 0 )
  1028.       return code;
  1029.     /* Check for a CTM we can handle. */
  1030.     if ( pdev->scale.x != pdev->scale.y )
  1031.       return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
  1032.                     pcpath);
  1033.     if ( pis->ctm.xy == 0 && pis->ctm.yx == 0 )
  1034.       { scale = fabs(pis->ctm.xx);
  1035.         if ( fabs(pis->ctm.yy) != scale )
  1036.           return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
  1037.                         pcpath);
  1038.       }
  1039.     else if ( pis->ctm.xx == 0 && pis->ctm.yy == 0 )
  1040.       { scale = fabs(pis->ctm.xy);
  1041.         if ( fabs(pis->ctm.yx) != scale )
  1042.           return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
  1043.                         pcpath);
  1044.       }
  1045.     else if ( (pis->ctm.xx == pis->ctm.yy && pis->ctm.xy == -pis->ctm.yx)||
  1046.           (pis->ctm.xx == -pis->ctm.yy && pis->ctm.xy == pis->ctm.yx)
  1047.         )
  1048.       scale = sqrt(pis->ctm.xx * pis->ctm.xx + pis->ctm.xy * pis->ctm.xy);
  1049.     else
  1050.       return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
  1051.                     pcpath);
  1052.     scale /= pdev->scale.x;
  1053.     pdf_put_clip_path(pdev, pcpath);
  1054.     pdf_set_color(pdev, gx_dc_pure_color(pdcolor), &pdev->stroke_color, "RG");
  1055.     if ( (float)(pis->line_params.dash.offset * scale) != pdev->line_params.dash.offset ||
  1056.          pattern_size != pdev->line_params.dash.pattern_size ||
  1057.          pattern_size > max_dash ||
  1058.          (pattern_size != 0 &&
  1059.           !pdf_dash_pattern_eq(pdev->dash_pattern, &pis->line_params.dash,
  1060.                    scale))
  1061.        )
  1062.       { pputs(s, "[ ");
  1063.         pdev->line_params.dash.pattern_size = pattern_size;
  1064.         for ( i = 0; i < pattern_size; ++i )
  1065.           { float element = pis->line_params.dash.pattern[i] * scale;
  1066.         if ( i < max_dash )
  1067.           pdev->dash_pattern[i] = element;
  1068.         pprintg1(s, "%g ", element);
  1069.           }
  1070.         pdev->line_params.dash.offset =
  1071.           pis->line_params.dash.offset * scale;
  1072.         pprintg1(s, "] %g d\n", pdev->line_params.dash.offset);
  1073.       }
  1074.     if ( params->flatness != pdev->flatness )
  1075.       { pprintg1(s, "%g i\n", params->flatness);
  1076.         pdev->flatness = params->flatness;
  1077.       }
  1078.     if ( (float)(pis->line_params.half_width * scale) != pdev->line_params.half_width )
  1079.       { pdev->line_params.half_width = pis->line_params.half_width * scale;
  1080.         pprintg1(s, "%g w\n", pdev->line_params.half_width * 2);
  1081.       }
  1082.     if ( pis->line_params.miter_limit != pdev->line_params.miter_limit )
  1083.       { pprintg1(s, "%g M\n", pis->line_params.miter_limit);
  1084.         gx_set_miter_limit(&pdev->line_params,
  1085.                    pis->line_params.miter_limit);
  1086.       }
  1087.     if ( pis->line_params.cap != pdev->line_params.cap )
  1088.       { pprintd1(s, "%d J\n", pis->line_params.cap);
  1089.         pdev->line_params.cap = pis->line_params.cap;
  1090.       }
  1091.     if ( pis->line_params.join != pdev->line_params.join )
  1092.       { pprintd1(s, "%d j\n", pis->line_params.join);
  1093.         pdev->line_params.join = pis->line_params.join;
  1094.       }
  1095.     code = pdf_put_path(pdev, ppath, false, NULL);
  1096.     if ( code < 0 )
  1097.       return code;
  1098.     pputs(s, (code ? "s\n" : "S\n"));
  1099.     return 0;
  1100. }
  1101.